package com.ltu.timkor6.gamesite.games.suduku.client;

import java.util.List;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.ltu.timkor6.gamesite.games.suduku.client.Cell;
import com.ltu.timkor6.gamesite.shared.DoubleArray;
import com.ltu.timkor6.gamesite.shared.CompositeAbstract;
import com.ltu.timkor6.gamesite.shared.Result;

/**
 * Suduku
 * 
 * @author tim
 */


public class SudukuComposite extends CompositeAbstract
{
	private static final String CSS_SUDUKU_TABLE = "suduku-table";
	private static final String CSS_SUDUKU_PANEL = "suduku-panel";
	private static final String CSS_SUDUKU_CELL = "suduku-cell";
	private static final String CSS_SUDUKU_LABEL = "suduku-label";
	private static final String CSS_SUDUKU_LABEL_LOCKED = "suduku-label-locked";
	
	private static final int SUDUKU_ROWS = 9;
	private static final int SUDUKU_COLUMNS = 9;
		
	private Suduku suduku;
	private SimplePanel info;
	private TextBox number;
	private SimplePanel content;
	private FlexTable game;
	
	private int emptyCells;
	private int currentMoves;
	
	private VerticalPanel infoPanel = new VerticalPanel();
	private Label labelEmptyCells = new Label();
	private Label labelCellsFilledIn;
	private DoubleArray array;
	
	public SudukuComposite(Suduku suduku)
	{
		this.suduku = suduku;
		
		// Title
		final Label title = new Label("Suduku");
		title.setStyleName("panelHeader");
		panel.add(title);
		
		info = new SimplePanel();
		info.setStyleName("game-info");
		content = new SimplePanel();
		content.setStyleName("game-playarea");
		
		panel.add(info);
		panel.add(content);
		
		//loadModule();
		suduku.start(0);
		
		initWidget(panel);
	}
	
	public void loadModule()
	{
		this.info.setStyleName("errors");
		VerticalPanel startPanel = new VerticalPanel();
		
		Label label = new Label("Number of elements");
		
		number = new TextBox();
		number.setText("3");
		number.addKeyPressHandler(new KeyPressHandler()
		{
			public void onKeyPress(KeyPressEvent event)
			{
				if(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER)
				{
					suduku.checkSubmit();
				}
			}
		});
		
		Button submit = new Button("Start!");
		submit.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event) {
				suduku.checkSubmit();
			}
		});
		
		startPanel.add(label);
		startPanel.add(number);
		startPanel.add(submit);
		
		content.setWidget(startPanel);
	}
	
	public String getNumber()
	{
		return this.number.getText();
	}
	
	public void addError(String error)
	{
		this.info.setWidget(new Label(error));
	}
	
	public void startGame()
	{
		this.info.setWidget(infoPanel);
		this.info.setStyleName("game-info");
		
		infoPanel.add(labelEmptyCells);
		
		labelCellsFilledIn = new Label("Cells filled in: 0");
		infoPanel.add(labelCellsFilledIn);
		
		// Set the outer bounds
		game = new FlexTable();
		game.setBorderWidth(1);
		game.setCellPadding(0);
		game.setCellSpacing(0);
		game.setStyleName(CSS_SUDUKU_TABLE);
		
		// Draw our playing field
		SimplePanel focusPanel;
		for(int row = 0; row < SUDUKU_ROWS; row++)
		{
			for(int column = 0; column < SUDUKU_COLUMNS; column++)
			{
				Integer value = this.array.get(row, column);
				
				// If the field should be writable
				boolean clickable = (value == null);
				
				focusPanel = createPanel(row, column, clickable);
				
				Cell cell = createCell(value, row, column);
				
				focusPanel.setWidget(cell);
			}
		}
		
		updateEmptyCells();
		
		content.setWidget(game);
	}
	
	/**
	 * Create a panel.
	 * @param column
	 * @param row
	 * @return
	 */
	private SimplePanel createPanel(int row, int column, boolean clickable)
	{
		SimplePanel focusPanel = new SimplePanel();
		focusPanel.setStyleName(CSS_SUDUKU_PANEL);
		
		// Make all panels accept clicks
		//focusPanel.addClickHandler(this.addClickPanel(row, column));
		
		// Add it to a cell
		game.setWidget(row, column, focusPanel);
		if((row == 2 || row == 5 || row == 8) && (column == 2 || column == 5 || column == 8))
		{
			game.getCellFormatter().addStyleName(row, column, "suduku-cell-corner");
		}
		else if(row == 2 || row == 5 || row == 8)
		{
			game.getCellFormatter().addStyleName(row, column, "suduku-cell-bottom");
		}
		else if(column == 2 || column == 5 || column == 8)
		{
			game.getCellFormatter().addStyleName(row, column, "suduku-cell-right");
		}
		else
		{
			game.getCellFormatter().addStyleName(row, column, CSS_SUDUKU_CELL);
		}
		
		return focusPanel;
	}
	
	/**
	 * Create a cell.
	 * @param element
	 * @param column
	 * @param row
	 * @return
	 */
	private Cell createCell(Integer value, int row, int column)
	{
		Cell cell;
		
		if(value == 0)
		{
			cell = new Cell("", row, column);
			cell.setStyleName(CSS_SUDUKU_LABEL);
			cell.setWritable(true);
			cell.addClickHandler(addClickCell(row, column));
			this.emptyCells++;
		}
		else
		{
			cell = new Cell(value, row, column);
			cell.setStyleName(CSS_SUDUKU_LABEL);
			cell.addStyleName(CSS_SUDUKU_LABEL_LOCKED);
			cell.setWritable(false);
		}
		
		return cell;
	}
	
	private void activeCell(final Cell source, final int row, final int column)
	{
		SimplePanel parent = (SimplePanel) source.getParent();
		parent.clear();
		
		TextBox text = new TextBox();
		text.setText(source.getText());
		text.setMaxLength(1);
		text.addFocusHandler(new FocusHandler()
		{
			public void onFocus(FocusEvent event)
			{
				TextBox text = (TextBox) event.getSource();
				text.selectAll();
			}
			
		});
		text.addBlurHandler(new BlurHandler()
		{
			public void onBlur(BlurEvent event)
			{
				TextBox text = (TextBox) event.getSource();
				cellBlur(source, text, row, column);
			}
		});
		parent.add(text);
		text.setFocus(true);
	}
	
	private void cellBlur(Cell source, TextBox text, int row, int column)
	{
		int value = 0;
		SimplePanel parent = (SimplePanel) text.getParent();
		
		try
		{
			value = Integer.parseInt(text.getText());
		}
		catch(NumberFormatException e)
		{
			
		}
		
		if(this.array.get(row, column) == 0 && 0 < value)
		{
			this.currentMoves++;
			updateMoves(row, column, value);
		}
		else if(0 < this.array.get(row, column) && value == 0)
		{
			this.currentMoves--;
			updateMoves(row, column, value);
		}
		
		String newText = (value == 0) ? "" : String.valueOf(value) ;
		source.setText(newText);
		parent.clear();
		parent.add(source);
	}
	
	public void finished(Result result)
	{
		if(result == null)
		{
			Window.alert("You failed");
		}
		else
		{
			Window.alert("Finished on " + this.currentMoves + " moves with " + result.getPoints() + " points.");
		}
	}
	
	private void updateMoves(int row, int column, int value)
	{
		this.array.set(row, column, value);
		this.labelCellsFilledIn.setText("Cells filled in: " + this.currentMoves);
		
		if(this.currentMoves == this.emptyCells)
		{
			this.suduku.finished(this.array);
		}
	}
	
	private ClickHandler addClickCell(final int row, final int column)
	{
		ClickHandler handler = new ClickHandler()
		{
			public void onClick(ClickEvent event)
			{
				Cell source = (Cell) event.getSource();
				
				if(source.isWritable())
				{
					activeCell(source, row, column);
				}
			}
		};
		return handler;
	}
	
	public void updateEmptyCells()
	{
		this.labelEmptyCells.setText("Empty cells: " + this.emptyCells);
	}

	public void setList(List<List<Integer>> list)
	{
		this.array = new DoubleArray(list);
	}
}
